import time
import struct
import logging
from queue import Queue
from utils.crc_calculator import CRCCalculator
from utils.data_utils import DataUtils


class ModbusRTUProtocol:
    """Modbus RTU协议处理类"""

    def __init__(self, serial_manager, config):
        self.serial_manager = serial_manager
        self.config = config
        self.crc_calc = CRCCalculator()
        self.data_utils = DataUtils()

        # 从配置获取参数
        modbus_config = config.get_modbus_config()
        self.device_address = modbus_config.get("device_address", 1)
        self.frame_interval = modbus_config.get("frame_interval", 3.5) / 1000.0  # 转换为秒
        self.response_timeout = modbus_config.get("response_timeout", 20) / 1000.0  # 转换为秒
        self.last_frame_time = 0

    def send_frame(self, function_code, data):
        """发送Modbus RTU帧"""
        # 构建帧
        frame = bytearray()
        frame.append(self.device_address)
        frame.append(function_code)
        frame.extend(data)

        # 计算CRC
        crc = self.crc_calc.calculate(frame)
        frame.append(crc & 0xFF)
        frame.append((crc >> 8) & 0xFF)

        # 确保帧间隔
        current_time = time.time()
        time_since_last = current_time - self.last_frame_time
        if time_since_last < self.frame_interval:
            time.sleep(self.frame_interval - time_since_last)

        # 发送帧
        self.serial_manager.send_data(frame)
        self.last_frame_time = time.time()

        # 记录发送日志
        hex_frame = ' '.join([f'{b:02X}' for b in frame])
        logging.info(f"发送 -> 地址: {self.device_address}, 功能: {function_code:02X}, 数据: {hex_frame}")
        return frame

    def receive_frame(self, timeout=None):
        """接收Modbus RTU响应帧"""
        timeout = timeout or self.response_timeout
        start_time = time.time()
        frame = bytearray()

        # 第一阶段：读取地址和功能码（2字节）
        while len(frame) < 2:
            if time.time() - start_time > timeout:
                logging.warning("接收帧超时 (阶段1)")
                return None

            data = self.serial_manager.receive_data()
            if data:
                frame.extend(data)

        # 检查地址是否匹配
        if frame[0] != self.device_address:
            logging.warning(f"地址不匹配: 期望 {self.device_address}, 实际 {frame[0]}")
            return None

        # 第二阶段：根据功能码读取剩余数据
        function_code = frame[1]

        # 正常响应
        if function_code in [0x03, 0x04]:  # 读保持寄存器/输入寄存器
            # 读取字节数 (1字节)
            while len(frame) < 3:
                if time.time() - start_time > timeout:
                    logging.warning("接收帧超时 (阶段2)")
                    return None

                data = self.serial_manager.receive_data()
                if data:
                    frame.extend(data)

            byte_count = frame[2]
            expected_length = 3 + byte_count + 2  # 地址+功能码+字节数+数据+CRC

            # 读取数据部分
            while len(frame) < expected_length:
                if time.time() - start_time > timeout:
                    logging.warning(f"接收帧超时 (阶段3), 期望长度: {expected_length}, 当前长度: {len(frame)}")
                    return None

                data = self.serial_manager.receive_data()
                if data:
                    frame.extend(data)

        # 异常响应
        elif function_code & 0x80:  # 异常响应
            expected_length = 5  # 地址+功能码+异常码+CRC

            while len(frame) < expected_length:
                if time.time() - start_time > timeout:
                    logging.warning("接收帧超时 (异常响应)")
                    return None

                data = self.serial_manager.receive_data()
                if data:
                    frame.extend(data)

        # 其他功能码
        else:
            logging.warning(f"未处理的功能码: {function_code:02X}")
            return None

        # 记录接收日志
        hex_frame = ' '.join([f'{b:02X}' for b in frame])
        logging.info(f"接收 <- 地址: {frame[0]}, 功能: {frame[1]:02X}, 数据: {hex_frame}")
        return frame

    def validate_frame(self, frame):
        """验证帧的CRC校验码"""
        if len(frame) < 2:
            return False

        # 分离数据和CRC
        data = frame[:-2]
        received_crc = frame[-2] | (frame[-1] << 8)

        # 计算CRC
        return self.crc_calc.verify(data, received_crc)

    def read_holding_registers(self, start_address, count):
        """读取保持寄存器"""
        data = self.data_utils.pack_register(start_address, count)
        self.send_frame(0x03, data)

        # 读取响应
        response = self.receive_frame()
        if not response:
            logging.warning("读取保持寄存器超时")
            return None

        # 验证响应
        if not self.validate_frame(response):
            logging.error("CRC校验失败")
            return None

        # 检查异常响应
        if response[1] & 0x80:
            exception_code = response[2]
            logging.error(f"异常响应: 代码 {exception_code}")
            return None

        # 解析数据
        byte_count = response[2]
        if byte_count != count * 2:
            logging.error(f"数据长度不匹配: 期望 {count * 2}, 实际 {byte_count}")
            return None

        # 返回寄存器值列表
        register_data = response[3:3 + byte_count]
        return self.data_utils.unpack_registers(register_data)

    def write_single_register(self, address, value):
        """写入单个寄存器"""
        data = self.data_utils.pack_register(address, value)
        self.send_frame(0x06, data)

        # 读取响应
        response = self.receive_frame()
        if not response:
            logging.warning("写入寄存器超时")
            return False

        # 验证响应
        if not self.validate_frame(response):
            logging.error("CRC校验失败")
            return False

        # 检查异常响应
        if response[1] & 0x80:
            exception_code = response[2]
            logging.error(f"异常响应: 代码 {exception_code}")
            return False

        # 验证写入的值
        resp_address = (response[2] << 8) | response[3]
        resp_value = (response[4] << 8) | response[5]

        if resp_address != address or resp_value != value:
            logging.error("写入寄存器验证失败")
            return False

        return True